;================================================================
;  fire.s
;               The Fire effect
;
;================================================================
;
; 25thanni, a demo dedicated to the 25th anniversary of the ZX81.
;
; (c)2006 Bodo Wenzel
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public
; License along with this program; if not, write to the Free
; Software Foundation Inc., 59 Temple Place, Suite 330, Boston,
; MA 02111-1307 USA
;================================================================

	.module	fire

;= Externals ====================================================

	.globl	heap_ptr
	.globl	text_file
	.globl	i_reg

	.globl	check_break
	.globl	set_show
	.globl	show_dummy
	.globl	vsync

	.globl	GREY_I_REG
	.globl	TEXT_ROWS,TEXT_COLUMNS,CHAR_WIDTH,CHAR_HEIGHT
	.globl	GREY_0,GREY_1,GREY_2,GREY_3
	.globl	GREY_4,GREY_5,GREY_6,GREY_7
	.globl	GREY_8,GREY_9,GREY_A,GREY_B
	.globl	GREY_C,GREY_D,GREY_E,GREY_F
	.globl	G0,G1,G2,G3,G4,G5,G6,G7,G8,G9,GA,GB,GC,GD,GE,GF
	.globl	__,X8,X9,XA,QU,PD,DL,CL,QM,LP,RP,GT,LT,EQ,PL,MI
	.globl	TI,SL,SC,CM,PE,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9
	.globl	_A,_B,_C,_D,_E,_F,_G,_H,_I,_J,_K,_L,_M,_N,_O,_P
	.globl	_Q,_R,_S,_T,_U,_V,_W,_X,_Y,_Z,NL,INV
	.globl	show_text
	.globl	t_in_up
	.globl	t_out_up
	.globl	t_ready
	.globl	render_char

	.globl	random

	.globl	unpack

;= Constants ====================================================

; double global definition checked by linker
TEXT_ROWS	==	24
TEXT_COLUMNS	==	32
CHAR_WIDTH	==	8
CHAR_HEIGHT	==	8

WIDTH		=	TEXT_COLUMNS
HEIGHT		=	TEXT_ROWS
BITS_PER_BYTE	=	CHAR_WIDTH
MAX_GREY	=	0x1F	; don't change this, code depends
				; on it; it's just for clarity
BITMAP_SIZE	=	CHAR_HEIGHT*(WIDTH/BITS_PER_BYTE+1)

FLASH_RATE	=	32	; loops until flash repeats
Y_FLASH		=	5	; top line of flashing fire
RANDOM_GREY	=	MAX_GREY>>1
Y_RANDOM	=	8	; line of random sparks
Y_SCROLL	=	15	; top line of scrolling fire

;= Program code =================================================

	.area	CODE

;- Show the Fire effect -----------------------------------------

fire::
	ld	hl,#show_dummy
	call	set_show

	ld	hl,#lookup
	ld	de,(heap_ptr)
	ld	bc,#MAX_GREY+1
	ldir			; lookup needs a 'paged' address

	ex	de,hl
	ld	(flash_bmp),hl
	ld	bc,#BITMAP_SIZE
	add	hl,bc		; more than needed, but OK
	ld	(scroll_bmp),hl
	ld	(hl),#0
	ld	e,l
	ld	d,h
	inc	de
	ldir
	ld	(off_screen),hl
	ld	bc,#HEIGHT*WIDTH
	ldir

	ld	(text_file),de	; 1 byte more than screen size

	ld	hl,#HEIGHT*(WIDTH+1)
	add	hl,de
	ld	(show_text),hl
	ld	de,#scroll_line
	ld	bc,#PAC_SL_SIZE
	call	unpack

	ld	hl,(flash_bmp)
	ld	c,#5
	ld	a,#_Z
	call	render_char
	inc	hl
	ld	a,#_X
	call	render_char
	inc	hl
	ld	a,#_8
	call	render_char
	inc	hl
	ld	a,#_1
	call	render_char

	ld	a,#BITS_PER_BYTE
	ld	(scroll_x),a
	ld	hl,#fire_line
	ld	(scroll_ptr),hl

	call	copy_off_screen

	call	t_in_up

	ld	a,#GREY_I_REG
	ld	(i_reg),a
	ld	hl,#show_text
	call	set_show

	call	t_ready

f_flash_loop:
	ld	b,#FLASH_RATE
f_fire_loop:
	push	bc

	call	check_break
	jr	nc,f_quit

;- shifting the scrolling text  - - - - - - - - - - - - - - - - -

	ld	hl,(scroll_bmp)
	ld	de,#BITMAP_SIZE
	add	hl,de
	ld	b,e
sh_loop:
	dec	hl
	rl	(hl)
	djnz	sh_loop

	ex	de,hl
	ld	bc,#Y_SCROLL*WIDTH
	call	copy_bmp

	ld	hl,#scroll_x
	dec	(hl)
	jr	nz,sh_quit

	ld	(hl),#BITS_PER_BYTE

	ld	hl,(scroll_ptr)
	ld	a,(hl)
	cp	#NL
	jr	z,f_quit

	inc	hl
	ld	(scroll_ptr),hl

	ld	hl,(scroll_bmp)
	ld	de,#WIDTH/BITS_PER_BYTE
	add	hl,de
	ld	c,#5
	call	render_char

sh_quit:

;- add some randomness, looks nicer - - - - - - - - - - - - - - -

	ld	hl,(off_screen)
	call	random
	ld	e,a
	ld	d,#(Y_RANDOM*WIDTH)>>8
	add	hl,de
	ld	a,(hl)
	and	a
	jr	z,rnd_quit
	or	#RANDOM_GREY
	ld	(hl),a
rnd_quit:

;- copy before the fire algorithm blurs the "pixels"  - - - - - -

	call	copy_off_screen

;- this is the fire algorithm - - - - - - - - - - - - - - - - - -

	ld	de,(off_screen)
	ld	hl,#WIDTH
	add	hl,de
	ld	c,#HEIGHT-1
f_loop1:
	ld	b,#WIDTH
f_loop2:
	ld	a,(hl)
	add	a,a
	add	a,a
	dec	hl
	add	a,(hl)
	inc	hl
	inc	hl
	add	a,(hl)
	rrca
	rrca
	rrca
	and	#MAX_GREY
	ld	(de),a
	inc	de
	djnz	f_loop2
	ld	b,#WIDTH
	dec	c
	jr	nz,f_loop1

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

	pop	bc
	djnz	f_fire_loop

	ld	de,(flash_bmp)
	ld	bc,#Y_FLASH*WIDTH
	call	copy_bmp

	jp	f_flash_loop

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

f_quit:
	pop	bc

	call	t_out_up
	jp	t_ready

;- Copy a text bitmap into the off_screen -----------------------
; BC offset into off-screen
; DE pointer to bitmap

copy_bmp:
	ld	hl,(off_screen)
	add	hl,bc
	ld	c,#CHAR_HEIGHT
cb_l_loop:

	.if	WIDTH/BITS_PER_BYTE-4
	.error	"Code depends on WIDTH/BITS_PER_BYTE=4"
	.endif

	ld	a,(de)
	inc	de
	ld	b,#BITS_PER_BYTE
cb_b1_loop:
	rla
	jr	nc,cb_b1_next
	ld	(hl),#MAX_GREY
cb_b1_next:
	inc	hl
	djnz	cb_b1_loop	; copy 1st byte

	ld	a,(de)
	inc	de
	ld	b,#BITS_PER_BYTE
cb_b2_loop:
	rla
	jr	nc,cb_b2_next
	ld	(hl),#MAX_GREY
cb_b2_next:
	inc	hl
	djnz	cb_b2_loop	; copy 2nd byte

	ld	a,(de)
	inc	de
	ld	b,#BITS_PER_BYTE
cb_b3_loop:
	rla
	jr	nc,cb_b3_next
	ld	(hl),#MAX_GREY
cb_b3_next:
	inc	hl
	djnz	cb_b3_loop	; copy 3rd byte

	ld	a,(de)
	inc	de
	ld	b,#BITS_PER_BYTE
cb_b4_loop:
	rla
	jr	nc,cb_b4_next
	ld	(hl),#MAX_GREY
cb_b4_next:
	inc	hl
	djnz	cb_b4_loop	; copy 4th byte

	inc	de
	dec	c
	jr	nz,cb_l_loop

	ret

;- Copy the off-screen via the grey lookup table into the screen

copy_off_screen:
	call	vsync		; avoid flicker

	ld	de,(heap_ptr)	; pointer to lookup table
	ld	hl,(off_screen)
	exx
	ld	hl,(text_file)
	ld	e,#NL
	ld	c,#HEIGHT
cos_olp:
	ld	b,#WIDTH
cos_ilp:
	exx
	ld	e,(hl)
	inc	hl
	ld	a,(de)
	exx
	ld	(hl),a
	inc	hl
	djnz	cos_ilp

	ld	(hl),e
	inc	hl
	dec	c
	jr	nz,cos_olp

	ret

;= Data =========================================================

lookup:				; maps values to character codes
	.db	GREY_F
	.db	GREY_E
	.db	GREY_E
	.db	GREY_D
	.db	GREY_D
	.db	GREY_C
	.db	GREY_C
	.db	GREY_B
	.db	GREY_B
	.db	GREY_A
	.db	GREY_A
	.db	GREY_9
	.db	GREY_9
	.db	GREY_8
	.db	GREY_8
	.db	GREY_7
	.db	GREY_7
	.db	GREY_7
	.db	GREY_6
	.db	GREY_6
	.db	GREY_6
	.db	GREY_5
	.db	GREY_5
	.db	GREY_4
	.db	GREY_4
	.db	GREY_3
	.db	GREY_3
	.db	GREY_2
	.db	GREY_2
	.db	GREY_1
	.db	GREY_1
	.db	GREY_0
	.if	.-lookup-MAX_GREY-1
	.error	"Lookup table has wrong size"
	.endif

fire_line:
	.db	_A,__,_H,_O,_T,__,_H,_E
	.db	_L,_L,_O,__,_T,_O,__,_M
	.db	_I,_N,_A,_S,PE,PE,PE,__
	.if	(.-fire_line)%(FLASH_RATE/BITS_PER_BYTE)
	.error	"Multiple of FLASH_RATE/BITS_PER_BYTE needed"
	.endif
	.db	__,__,__,__,__,NL

scroll_line:
	.include	"fire_sl.inc"
PAC_SL_SIZE	=	.-scroll_line
UNP_SL_SIZE	=	UNPACKED

;= Variables ====================================================

	.area	SCRATCH	(ovr)

flash_bmp:
	.dw	0
scroll_bmp:
	.dw	0
scroll_x:
	.db	0
scroll_ptr:
	.dw	0
off_screen:
	.dw	0

;= Heap usage ===================================================

;		lookup table value -> character
HEAP =		MAX_GREY+1
;		flashing bitmap
HEAP =	HEAP +	BITMAP_SIZE
;		scrolling bitmap
HEAP =	HEAP +	BITMAP_SIZE
;		off screen value map
HEAP =	HEAP +	HEIGHT*WIDTH+1
;		display file
HEAP =	HEAP +	HEIGHT*(WIDTH+1)
;		unpacked scroll text
HEAP =	HEAP +	UNP_SL_SIZE

	.area	HEAP	(abs,ovr)
	.ds	HEAP

;= The end ======================================================
